<script>
import ascending from './icons/ascending.png'

import descending from './icons/descending.png'

import defaultSort from './icons/default-sort.png'

import FilterInput from './FilterInput'

export default {
  name: 'Thead',

  components: { FilterInput },

  props: {
    rowHeight: {
      type: Number,
      default: 0
    },

    structure: {
      type: Array,
      default: () => []
    },

    bottomList: {
      type: Array,
      default: () => []
    },

    tableWidth: {
      type: Number,
      default: 0
    },

    getTHeadHeight: {
      type: Function
    },

    sortInfo: {
      type: Object,
      default: () => {}
    },

    updateSelectSortTd: {
      type: Function
    },

    headerCellStyle: {
      type: Function
    },

    updateLinePosition: {
      type: Function
    },

    showFilterPopover: {
      type: Function
    },

    filterPool: {
      type: Array,
      default: () => []
    },

    filterable: {
      type: Boolean,
      default: false
    },

    updateFilterPool: {
      type: Function
    }
  },

  data() {
    return {
      dragInfo: {
        isDraging: false,
        currentClientX: 0,
        currentTd: {},
        distance: 0,
        parentLeft: 0
      }
    }
  },

  methods: {
    /*
      + 对结构化的数据再进行整理
      1.0-[]
      2.1-[]
      3.3-[]
      4....
    */
    arrange(structure = [], templateData = {}) {
      for (let i = 0, len = structure.length; i < len; i++) {
        const current = structure[i]
        templateData[current.depth] = templateData[current.depth]
          ? [...templateData[current.depth], current]
          : [current]
        if (current.children) {
          this.arrange(current.children, templateData)
        }
      }
      return templateData
    },

    tdDivStyle(currentTd) {
      if (this.headerCellStyle) {
        return this.headerCellStyle({ col: currentTd.col, depth: currentTd.depth, td: currentTd })
      } else {
        return ''
      }
    },

    makeTd(currentTd) {
      // 是否是最底层td
      const isBottomTd = this.bottomList.findIndex(item => item.id === currentTd.id) > -1

      if (isBottomTd) {
        return (
          <td
            style={{ width: currentTd.width + 'px', height: this.rowHeight + 'px' }}
            colSpan={currentTd.colSpan}
            rowSpan={currentTd.rowSpan}
            onMousedown={e => {
              this.handlerMousedownTd(e, currentTd)
            }}
            onMousemove={this.handlerMousemoveTd}
          >
            <div class="td-div" style={this.tdDivStyle(currentTd)}>
              {currentTd.label}
              {this.sortIcon(currentTd)}
            </div>
          </td>
        )
      } else {
        return (
          <td
            style={{ width: currentTd.width + 'px', height: this.rowHeight + 'px' }}
            colSpan={currentTd.colSpan}
            rowSpan={currentTd.rowSpan}
            onMousedown={e => {
              this.handlerMousedownTd(e, currentTd)
            }}
            onMousemove={this.handlerMousemoveTd}
          >
            <div class="td-div" style={this.tdDivStyle(currentTd)}>
              {currentTd.label}
            </div>
          </td>
        )
      }
    },

    /* 返回tr集合 */
    makeTrList(templateData = {}, trList = []) {
      for (const key in templateData) {
        const currentList = templateData[key]
        trList.push(
          <tr>
            {currentList.map(currentItem => {
              return this.makeTd(currentItem)
            })}
          </tr>
        )
      }
      return trList
    },

    filterTr() {
      if (this.filterable) {
        const tdList = this.bottomList.map(item => {
          return (
            <td style={{ width: item.width + 'px', height: this.rowHeight + 'px' }}>
              <div class="td-div">
                <FilterInput
                  currentTd={item}
                  filterPool={this.filterPool}
                  updateFilterPool={this.updateFilterPool}
                  showFilterPopover={this.showFilterPopover}
                />
              </div>
            </td>
          )
        })
        return <tr>{tdList}</tr>
      } else {
        return ''
      }
    },

    makeColgroup() {
      return (
        <colgroup>
          {this.bottomList.map(item => (
            <col width={item.width} />
          ))}
        </colgroup>
      )
    },

    sortIcon(currentTd) {
      if ('sort' in currentTd) {
        if (this.sortInfo.selectSortTd.id == currentTd.id) {
          let src = ''
          switch (this.sortInfo.type) {
            case 'ascending':
              src = ascending
              break
            case 'descending':
              src = descending
              break
            default:
              src = defaultSort
          }
          return (
            <img
              class="sorting"
              src={src}
              onClick={this.updateSelectSortTd.bind(this, currentTd, this.sortInfo.type)}
            />
          )
        } else {
          return (
            <img
              class="sorting"
              src={defaultSort}
              onClick={this.updateSelectSortTd.bind(this, currentTd, 'default')}
            />
          )
        }
      }
    },

    // 是否民中td的边缘区域
    isHitArea(e) {
      const distance = e.offsetX
      const target = e.target
      return distance >= target.getBoundingClientRect().width - 5
    },

    handlerMousedownTd(e, currentTd) {
      if (!this.isHitArea(e)) {
        return (this.dragInfo.isDraging = false)
      }
      this.dragInfo.isDraging = true

      const targetRect = e.target.getBoundingClientRect()

      const parentLeft = this.$refs.tHead.parentNode.parentNode.getBoundingClientRect().left

      this.dragInfo.parentLeft = parentLeft

      this.dragInfo.currentTd = currentTd

      this.dragInfo.currentClientX = targetRect.right
    },

    handlerMousemoveTd(e) {
      if (this.dragInfo.isDraging) return
      if (e.path[0].className !== 'td-div') return
      if (this.isHitArea(e)) {
        e.target.style.cursor = 'col-resize'
      } else {
        e.target.style.cursor = ''
      }
    },

    handlerMousemoveTable(e) {
      if (!this.dragInfo.isDraging) return
      let moveLeft = e.clientX - this.dragInfo.parentLeft
      this.updateLinePosition({
        left: moveLeft,
        show: 'block'
      })
    },

    handlerMouseupTable(e) {
      if (this.dragInfo.isDraging) {
        this.dragInfo.isDraging = false
        const distance = e.clientX - this.dragInfo.currentClientX + this.dragInfo.currentTd.width
        this.updateLinePosition({
          tdId: this.dragInfo.currentTd.id,
          show: 'none',
          distance: Math.floor(distance > 100 ? distance : 100)
        })
      }
    }
  },

  created() {
    window.addEventListener('mouseup', this.handlerMouseupTable)
    window.addEventListener('mousemove', this.handlerMousemoveTable)
  },

  beforeDestroy() {
    window.removeEventListener('mouseup', this.handlerMouseupTable)
    window.removeEventListener('mousemove', this.handlerMousemoveTable)
  },

  mounted() {
    this.$nextTick(() => {
      const tHead = this.$refs.tHead.getBoundingClientRect().height
      this.getTHeadHeight(tHead)
    })
  },

  updated() {
    this.$nextTick(() => {
      const tHead = this.$refs.tHead.getBoundingClientRect().height
      this.getTHeadHeight(tHead)
    })
  },

  render() {
    if (this.structure.length > 0) {
      const result = this.arrange(this.structure)

      return (
        <table class="t-head" ref="tHead" style={{ width: this.tableWidth + 'px' }}>
          {this.makeColgroup()}
          {this.makeTrList(result)}
          {this.filterTr()}
        </table>
      )
    } else {
      return <div>Empty...</div>
    }
  }
}
</script>
<style scoped>
.t-head {
  border-collapse: collapse;
  border-top: 1px solid #ebeef5;
  border-left: 1px solid #ebeef5;
  table-layout: fixed;
}

.t-head td {
  padding: 0;
  position: relative;
  user-select: none;
}

.t-head .td-div {
  position: absolute;
  top: 0;
  bottom: 0;
  left: 0;
  right: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  border-right: 1px solid #ebeef5;
  border-bottom: 1px solid #ebeef5;
  background-color: #e4e4e4;
  font-weight: bold;
  font-size: 12px;
  color: #909399;
  overflow: hidden;
  white-space: nowrap;
}

.t-head .td-div .sorting {
  width: 13px;
  height: 13px;
  margin-left: 5px;
  cursor: pointer;
}
</style>
